package stream.demo01;

import com.google.gson.Gson;
import lombok.ToString;
import org.junit.Test;
import org.omg.CORBA.PUBLIC_MEMBER;
import stream.demo02.Student;

import java.text.Collator;
import java.text.NumberFormat;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import static java.util.stream.Collectors.toList;

/**
 * @author 真香
 * @create 2021-07-04 18:11
 */
public class demo01 {

    public List<Person> createSourceData(){
        List<Person> list = new ArrayList<>();
        list.add(new Person("jack", 20));
        list.add(new Person("mike", 25));
        list.add(new Person("tom", 30));
        return list;
    }


    /**
     * filter(T -> boolean)
     * 保留 boolean 为 true 的元素
     * 保留年龄为 20 的 person 元素
     */
    @Test
    public void test01(){

        List<Person> sourceData = this.createSourceData();
        List<Person> filterList = sourceData.stream().filter(Person -> Person.getAge() == 20).collect(toList());
        System.out.println(filterList);

    }

    /**
     * sorted() / sorted((T, T) -> int)
     *  如果流中的元素的类实现了 Comparable 接口，即有自己的排序规则，那么可以直接调用 sorted() 方法对元素进行排序，如 Stream<Integer>
     * 反之, 需要调用 sorted((T, T) -> int) 实现 Comparator 接口
     *
     * 作者：一叶知秋_zgx
     * 链接：https://www.jianshu.com/p/24af4f3ab046
     * 来源：简书
     * 著作权归作者所有。商业转载请联系作者获得授权，非商业转载请注明出处。
     */
    @Test
    public void test02(){
        List<Person> sourceData = this.createSourceData();
        //List<Person> sorterdList = sourceData.stream().sorted((p1, p2) -> p1.getAge() - p2.getAge()).collect(toList());
        List<Person> sorterdList = sourceData.stream().sorted(Comparator.comparing(Person::getAge)).collect(toList());

        System.out.println(sorterdList);

    }

    /**
     * limit(long n)
     * 返回前 n 个元素
     */
    @Test
    public void test03(){
        List<Person> sourceData = this.createSourceData();
        List<Person> list = sourceData.stream().limit(2).collect(toList());
        System.out.println(list);
    }


    /**
     * skip(long n)
     * 去除前 n 个元素
     */
    @Test
    public void test04(){
        List<Person> sourceData = this.createSourceData();
        List<Person> list = sourceData.stream().skip(2).collect(toList());
        System.out.println(list);
    }


    /**
     * limit(n)
     * skip(m)
     * 用在 limit(n) 前面时，先去除前 m 个元素再返回剩余元素的前 n 个元素
     * limit(n) 用在 skip(m) 前面时，先返回前 n 个元素再在剩余的 n 个元素中去除 m 个元素
     */
    @Test
    public void test05() {

        List<Person> sourceData = this.createSourceData();
        List<Person> list = sourceData.stream().limit(3).skip(1).collect(toList());
        System.out.println(list);


    }

    /**
     * map(T -> R)
     * 将流中的每一个元素 T 映射为 R（类似类型转换）
     * 返回list 里面的元素为 list 中每一个 Person 对象的 name 变量
     */
    @Test
    public void test06(){
        List<Person> sourceData = this.createSourceData();
        List<Integer> list = sourceData.stream().map(Person::getAge).collect(toList());
        System.out.println(list);

    }

    /**
     * flatMap(T -> Stream<R>)
     * 将流中的每一个元素 T 映射为一个流，再把每一个流连接成为一个流
     *
     */
    @Test
    public void test07(){
        List<String> list = new ArrayList<>();
        list.add("aaa bbb ccc");
        list.add("ddd eee fff");
        list.add("ggg hhh iii");

        List<String> list1 = list.stream().map(s -> s.split(" ")).flatMap(Arrays::stream).collect(toList());
        System.out.println(list1);

        /**
         * 上面例子中，我们的目的是把 List 中每个字符串元素以" "分割开，变成一个新的 List<String>。
         * 首先 map 方法分割每个字符串元素，但此时流的类型为 Stream<String[ ]>，因为 split 方法返回的是 String[ ] 类型；所以我们需要使用 flatMap 方法，先使用Arrays::stream将每个 String[ ] 元素变成一个 Stream<String> 流，然后 flatMap 会将每一个流连接成为一个流，最终返回我们需要的 Stream<String>
         *
         * 作者：一叶知秋_zgx
         * 链接：https://www.jianshu.com/p/24af4f3ab046
         * 来源：简书
         * 著作权归作者所有。商业转载请联系作者获得授权，非商业转载请注明出处。
         */
    }


    /**
     * anyMatch(T -> boolean)
     * 流中是否有一个元素匹配给定的 T -> boolean 条件
     * 是否存在一个 person 对象的 age 等于 20：
     * 返回值 true&false
     *
     *
     * allMatch(T -> boolean)
     * 流中是否所有元素都匹配给定的 T -> boolean 条件
     *
     * noneMatch(T -> boolean)
     * 流中是否没有元素匹配给定的 T -> boolean 条件
     *
     * findAny() 和 findFirst()
     *
     * findAny()：找到其中一个元素 （使用 stream() 时找到的是第一个元素；使用 parallelStream() 并行时找到的是其中一个元素）
     * findFirst()：找到第一个元素
     *
     * 值得注意的是，这两个方法返回的是一个 Optional<T> 对象，它是一个容器类，能代表一个值存在或不存在
     *
     */
    @Test
    public void test08(){

        List<Person> sourceData = this.createSourceData();
        boolean b = sourceData.stream().anyMatch(Person -> Person.getAge() == 20);
        System.out.println(b);


    }

    /**
     * reduce((T, T) -> T) 和 reduce(T, (T, T) -> T)
     * 用于组合流中的元素，如求和，求积，求最大值等
     */
    @Test
    public void test09(){
        List<Person> sourceData = this.createSourceData();
        // 计算年龄总和 其中，reduce 第一个参数 0 代表起始值为 0，lambda (a, b) -> a + b 即将两值相加产生一个新值
        //Integer reduce = sourceData.stream().map(person -> person.getAge()).reduce(0, (a, b) -> a + b);
        // 与之相同
       // Integer reduce = sourceData.stream().map(Person::getAge).reduce(0, Integer::sum);


        //计算年龄总乘积：
        // int reduce = sourceData.stream().map(Person::getAge).reduce(1, (a, b) -> a * b);
        //当然也可以 即不接受任何起始值，但因为没有初始值，需要考虑结果可能不存在的情况，因此返回的是 Optional 类型
        Optional<Integer> reduce = sourceData.stream().map(Person::getAge).reduce(Integer::sum);

        System.out.println(reduce);

    }

    /**
     * 统计元素个数
     */
    @Test
    public void test10(){
        List<Person> sourceData = this.createSourceData();
        long count = sourceData.stream().count();
        System.out.println(count);
    }

    /**
     * 打印元素
     */
    @Test
    public void test11(){
        List<Person> sourceData = this.createSourceData();
        sourceData.stream().forEach(System.out::println);
    }



    @Test
    public void listCreateStream(){

        // 创建集合
        List<String> list = Arrays.asList("张三", "李四", "王五");
        // 创建一个串行流  串行流，由主线程按顺序对流执行操作
        /**
         * 串行流可以通过parallel()方法把顺序流转换成并行流。
         */
        Stream<String> stream = list.stream();
        // 创建一个并行流
        /**
         * 并行流，内部以多线程并行执行的方式对流进行操作，但前提是流中的数据处理没有顺序要求。
         * 例如计算集合中的数量之和。如果流种数据量很大，并行流可以加快处理速度。
         */
        Stream<String> stringStream = list.parallelStream();

    }

    @Test
    public void arrayCreateStream(){

        // 创建数组
        String[] persons = {"张三", "李四", "王五"};
        // 创建串行流
        Stream<String> stream = Arrays.stream(persons);
        // 创建并行流
        Stream<String> parallel = Arrays.stream(persons).parallel();
    }

    @Test
    public void streamStaticMethodCreateStream() {
        Stream<String> stream2 = Stream.of("张三", "李四", "王五");

        // 输出五个奇数
        Stream<Integer> integerStream = Stream.iterate(1, x -> x + 2).limit(2);
        integerStream.forEach(System.out::println);

        // 生成2个UUID
        Stream<UUID> uuidStream = Stream.generate(UUID::randomUUID).limit(2);
        uuidStream.forEach(System.out::println);
    }


    @Test
    public void forEach() {
        List<Student> students = new ArrayList<>(16);
        students.add(new Student("1", "张三", 18, "male", 88));
        students.add(new Student("2", "李四", 17, "male", 60));
        students.add(new Student("3", "王五", 18, "male", 100));
        students.add(new Student("4", "赵六", 20, "male", 10));
        students.add(new Student("5", "董七", 14, "female", 95));
        students.add(new Student("6", "幺八", 21, "male", 55));
        students.add(new Student("7", "老九", 20, "female", 66));
        students.add(new Student("8", "小明", 18, "male", 100));
        students.add(new Student("9", "小红", 22, "female", 95));
        students.add(new Student("10", "小张", 25, "male", 90));

        // students.forEach(System.out::println);
        /**
         *  过滤出成绩100分的学生
         */
        List<Student> students1 = students.stream().filter(student -> student.getScore() == 100).collect(Collectors.toList());
        students1.forEach( student ->{
            String name = student.getName();
            System.out.println(name+"分数==:"+student.getScore());
        });

        /** 串行流，匹配第一个
         * findFirst 找到第一个元素
         */
        Optional<Student> studentOptional =
                students.stream().filter(student -> student.getAge() >= 20).findFirst();
        if (studentOptional.isPresent()) {
            Student student = studentOptional.get();
            // System.out.println(student);
        }
        // studentOptional.ifPresent(System.out::println);


        // 并行流，匹配任意一个，findAny一般用于并行流
        Optional<Student> studentOptiona2 =
                students.parallelStream().filter(student -> student.getAge() >= 20).findAny();
        // studentOptiona2.ifPresent(System.out::println);


        //======================= 匹配 match=================================
        // 是否存在100分的学生
        boolean anyMatch = students.stream().anyMatch(student -> student.getScore() == 100);
        // 是否全部学生都100分
        boolean allMatch = students.stream().allMatch(student -> student.getScore() == 100);
        // // 是否全部学生都没有100分
        boolean noneMatch = students.stream().noneMatch(student -> student.getScore() == 100);
        //System.out.println(anyMatch);
        //System.out.println(allMatch);
        //System.out.println(noneMatch);

    }

    @Test
    public void testArrayListRe(){

        List<String> list1 = new ArrayList<>(3);
        list1.add("name");
        list1.add("age");
        list1.add("phone");
        list1.add("address");
        list1.add("sex");
        list1.add("tal");
        list1.add("color");
        list1.add("city");

        list1.add("language");
        list1.add("employee");
        list1.add("level");
        list1.add("Education");

        List<String> list = list1.stream().collect(Collectors.toList());

    }


    @Test
    public   void numberFormat() {
        double d = 12345.676688000;
        NumberFormat nf = NumberFormat.getNumberInstance();
        System.out.println(nf.format(d));//12,345.677 默认只保留到小数点后三位
        nf.setMinimumIntegerDigits(2);
        System.out.println(nf.format(d));//12,345.677 整数部分大于2位按默认最大小数位数3位输出
        d = 1234.0;
        nf.setMaximumIntegerDigits(3);
        System.out.println(nf.format(d));//234
        nf = NumberFormat.getInstance();
        d = 12345.6766;
        nf.setMinimumFractionDigits(1);
        System.out.println(nf.format(d));//12,345.677 小数部分大于1位，按默认最大小数位数3位输出
        nf.setMinimumFractionDigits(5);
        System.out.println(nf.format(d));//12,345.67660 不够位数补0
        nf.setMaximumFractionDigits(1);
        System.out.println(nf.format(d));//12,345.7
        nf = NumberFormat.getNumberInstance(Locale.US);
        d = 12345.6789;
        System.out.println(nf.format(d));//12,345.679
        nf = NumberFormat.getNumberInstance(Locale.FRANCE);
        System.out.println(nf.format(d));//12 345,679
    }

    @Test
    public void test(){
        String permissionList = "1";
        List<Long> secondClassifyIdList= Arrays.asList(permissionList.split(",")).stream().map(s -> Long.valueOf(s)).collect(Collectors.toList());
        System.out.println(secondClassifyIdList);
    }

    @Test
    public void testSort(){
        List<Question>  list = new ArrayList<>();
        list.add(new Question("A","羊得意"));
        list.add(new Question("C","扬得意"));
        list.add(new Question("D","杨得意"));
        list.add(new Question("B","洋得意"));
        list.add(new Question("F","洋得意"));
        list.add(new Question("E","洋得意"));
        list.add(new Question("J","洋得意"));
        list.add(new Question("K","洋得意"));
        list.add(new Question("H","洋得意"));
        list.add(new Question("O","洋得意"));
        list.add(new Question("Q","洋得意"));


        Comparator comparator = Collator.getInstance(Locale.CHINA);
        Collections.sort(list, new Comparator<Question>() {
            @Override
            public int compare(Question o1, Question o2) {
                return comparator.compare(o1.getChoose(), o2.getChoose());
            }
        });
        list.forEach(s-> System.out.println(s));
    }


    @ToString
    public static class Question {
        private String choose;
        private String value;

        public Question(String choose, String value) {
            this.choose = choose;
            this.value = value;
        }

        public String getChoose() {
            return choose;
        }

        public void setChoose(String choose) {
            this.choose = choose;
        }

        public String getValue() {
            return value;
        }

        public void setValue(String value) {
            this.value = value;
        }


    }



    @Test
    public void random(){
        HashMap<Object, Object> objectObjectHashMap = new HashMap<>();
        List<String> list = new ArrayList<String>();
        list.add("1");
        list.add("2");
        list.add("3");
        list.add("4");
        list.add("5");
        System.out.println("前：");
        for (int i = 0; i < list.size(); i++) {
            System.out.print(list.get(i) + "  ");
        }
        System.out.println("");
        System.out.println("后：");
        Collections.shuffle(list);
        for (int i = 0; i < list.size(); i++) {
            System.out.print(list.get(i) + "    ");
        }
    }

    @Test
    public void testGson(){
        Gson gson = new Gson();
        Person person = new Person("zhansan",67);
        String s = gson.toJson(person);
        System.out.println(s);
    }


}
